package com.xbongbong.paas.service.dynamic.crm.strategy;

import com.alibaba.dingtalk.openapi.newmessage.entity.OA;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.message.domain.entity.PushEntity;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.help.FormDataHelp;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.log.constant.CrmLogMemoConstant;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataDeleteBatchDTO;
import com.xbongbong.paas.pojo.dto.FormDataUpdateBatchDTO;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.service.dynamic.crm.strategy.impl.CommunicatePlanDynamicStrategyImpl;
import com.xbongbong.paas.service.dynamic.crm.strategy.impl.ContactDynamicStrategyImpl;
import com.xbongbong.paas.service.dynamic.crm.strategy.impl.ContractDynamicStrategyImpl;
import com.xbongbong.paas.service.dynamic.crm.strategy.impl.InvoiceDynamicStrategyImpl;
import com.xbongbong.paas.service.dynamic.crm.strategy.impl.OpportunityDynamicStrategyImpl;
import com.xbongbong.paas.service.dynamic.crm.strategy.impl.PayDynamicStrategyImpl;
import com.xbongbong.paas.service.dynamic.crm.strategy.impl.PaymentSheetDynamicStrategyImpl;
import com.xbongbong.paas.service.dynamic.crm.strategy.impl.QuotationDynamicStrategyImpl;
import com.xbongbong.paas.service.dynamic.crm.strategy.impl.RefundDynamicStrategyImpl;
import com.xbongbong.paas.service.dynamic.crm.strategy.impl.WorkOrderDynamicStrategyImpl;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.parent.abstracts.AbstractBusinessDynamicStrategy;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.customercommunicate.pojo.dto.DynamicDTO;
import com.xbongbong.pro.decisiontree.pojo.dto.DecisionTreeSaveDTO;
import com.xbongbong.pro.domain.entity.LabelEntity;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicArchiveDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicCheckJoinTeamDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicDecisionTreeDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicDeleteDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicDeleteLinkData;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicLabelDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicLinkDataStageJump;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicPushNotifyAddDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicPushNotifyDeleteDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicRefInfoDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicSaveDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicUpdateBatchDTO;
import com.xbongbong.pro.listbatch.pojo.dto.AddLabelDTO;
import com.xbongbong.pro.listbatch.pojo.dto.AddMainUserDTO;
import com.xbongbong.pro.listbatch.pojo.dto.ArchiveDTO;
import com.xbongbong.pro.listbatch.pojo.dto.DelRemindDTO;
import com.xbongbong.pro.message.model.PushModel;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.domain.entity.DynamicEntity;
import com.xbongbong.saas.domain.entity.competitor.SimpleDynamicEntity;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.ProjectLogEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.base.CommunicateBaseEnum;
import com.xbongbong.saas.model.DynamicModel;
import com.xbongbong.saas.model.LabelModel;
import com.xbongbong.saas.model.SimpleDynamicModel;
import com.xbongbong.sys.domain.entity.UserEntity;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 *抽象动态策略
 *
 *@author weijianxun
 */
public abstract class AbstractDynamicStrategy extends AbstractBusinessDynamicStrategy {
    private static final Logger LOG = LoggerFactory.getLogger(AbstractDynamicStrategy.class);
    @Resource
    private DynamicModel dynamicModel;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private PushModel pushModel;
    @Resource
    private LabelModel labelModel;
    @Resource
    private FormDataHelp formDataHelp;
    @Resource
    private SimpleDynamicModel simpleDynamicModel;

    /**
     * 动态批量更新
     * @param dynamicUpdateBatchDTO
     */
    protected void batchUpdate(DynamicUpdateBatchDTO dynamicUpdateBatchDTO, Integer logType) {
        FormDataUpdateBatchDTO formDataUpdateBatchDTO = dynamicUpdateBatchDTO.getFormDataUpdateBatchDTO();
        List<Long> dataIdList = dynamicUpdateBatchDTO.getAllowUpdateDataIds();
        initUpdateDynamicDto(formDataUpdateBatchDTO, dataIdList, ProjectLogEnum.getBySubType(logType));
    }

    private void initUpdateDynamicDto(FormDataUpdateBatchDTO formDataUpdateBatchDTO, List<Long> dataIdList, ProjectLogEnum projectLogEnum) {
        PaasFormEntity paasForm = getPaasForm(formDataUpdateBatchDTO.getCorpid(), formDataUpdateBatchDTO.getFormId(), formDataUpdateBatchDTO.getBusinessType());
        List<DynamicDTO> dynamicDTOS = new ArrayList<>(dataIdList.size());
        for (Long dataId : dataIdList) {
            DynamicDTO dynamicDTO = DynamicDTO.initDynamicDTO(formDataUpdateBatchDTO.getUserId(), CrmLogMemoConstant.DYNAMIC_USER_UPDATE_BASE_INFO, projectLogEnum.getSubType(),
                    DynamicDTO.initMemoHolder(formDataUpdateBatchDTO.getLoginUserName(), paasForm.getName()), paasForm, formDataUpdateBatchDTO.getSaasMark());
            initMainBusinessIdOrRefIdByLogType(projectLogEnum.getSubType(), dynamicDTO, dataId);
            dynamicDTOS.add(dynamicDTO);
        }
        insertDynamic(dynamicDTOS, formDataUpdateBatchDTO.getCorpid());
    }

    /**
     * 归档
     * @param dynamicArchiveDTO
     */
    protected void archive(DynamicArchiveDTO dynamicArchiveDTO, Integer logType) {
        ArchiveDTO archiveDTO = dynamicArchiveDTO.getArchiveDTO();
        List<PaasFormDataEntityExt> getByIdInAndDel = dynamicArchiveDTO.getGetByIdInAndDel();
        initArchiveDynamicDto(archiveDTO, getByIdInAndDel, ProjectLogEnum.getBySubType(logType));
    }

    private void initArchiveDynamicDto(ArchiveDTO archiveDTO, List<PaasFormDataEntityExt> getByIdInAndDel, ProjectLogEnum subType) {
        //项目动态日志
        List<DynamicDTO> dynamicDTOS = new ArrayList<>(getByIdInAndDel.size());
        String memo = null;
        if (1 == archiveDTO.getArchived()) {
            memo = CrmLogMemoConstant.DYNAMIC_USER_ARCHIVE;
        } else {
            memo = CrmLogMemoConstant.DYNAMIC_USER_CANCEL_ARCHIVE;
        }
        PaasFormEntity paasForm = null;
        for (PaasFormDataEntityExt formDataEntityExt : getByIdInAndDel) {
            if (paasForm == null) {
                paasForm = getPaasForm(archiveDTO.getCorpid(), formDataEntityExt.getFormId(), archiveDTO.getBusinessType());
            }
            DynamicDTO dynamicDTO = DynamicDTO.initDynamicDTO(archiveDTO.getUserId(), memo, subType.getSubType(), DynamicDTO.initMemoHolder(archiveDTO.getLoginUserName(), paasForm.getName()), paasForm, archiveDTO.getSaasMark());
            initMainBusinessIdOrRefIdByLogType(subType.getSubType(), dynamicDTO, formDataEntityExt.getDataId());
            dynamicDTOS.add(dynamicDTO);
        }
        insertDynamic(dynamicDTOS, archiveDTO.getCorpid());
    }

    /**
     * 查重加入团队
     * @param dynamicCheckJoinTeamDTO
     */
    protected void checkJoinTeam(DynamicCheckJoinTeamDTO dynamicCheckJoinTeamDTO, Integer logType) {
        AddMainUserDTO addMainUserDTO = dynamicCheckJoinTeamDTO.getAddMainUserDTO();
        List<Long> customerIds = addMainUserDTO.getDataIdList();
        if(CollectionUtils.isNotEmpty(customerIds)) {
            List<DynamicDTO> dynamicCustomerDTOS = new ArrayList<>(customerIds.size());
            PaasFormEntity paasForm = getPaasForm(addMainUserDTO.getCorpid(), addMainUserDTO.getFormId(), addMainUserDTO.getBusinessType());
            for (Long customerId : customerIds) {
                DynamicDTO dynamicDTO = DynamicDTO.initDynamicDTO(addMainUserDTO.getUserId(), CrmLogMemoConstant.DYNAMIC_USER_RECHECK_JOIN_TEAM, logType, DynamicDTO.initMemoHolder(addMainUserDTO.getLoginUserName()),
                        paasForm, addMainUserDTO.getSaasMark());
                initMainBusinessIdOrRefIdByLogType(logType, dynamicDTO, customerId);
                dynamicCustomerDTOS.add(dynamicDTO);
            }
            insertDynamic(dynamicCustomerDTOS, addMainUserDTO.getCorpid());
        }
    }

    /**
     * dynamicDTO需要包含 cropid
     * @param list
     * @param errorMsg
     */
    protected void insertDynamicAndDtoIncludeCorpid(List<DynamicDTO> list, String errorMsg) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        List<DynamicEntity> dynamicEntities = new ArrayList<>(list.size());

        Map<String, List<DynamicDTO>> corpidToDTOsMap = list.stream().collect(Collectors.groupingBy(DynamicDTO::getCorpid));
        corpidToDTOsMap.forEach((corpid, dtos) -> fillDynamicEntitysUseDTO(dtos, dynamicEntities, corpid));
        dynamicModel.insertBatch(dynamicEntities);
    }

    protected void insertDynamic(List<DynamicDTO> list, String corpid) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        List<DynamicEntity> dynamicEntities = new ArrayList<>(list.size());

        fillDynamicEntitysUseDTO(list, dynamicEntities, corpid);
        dynamicModel.insertBatch(dynamicEntities);
    }

    protected void insertSimpleDynamic(List<DynamicDTO> list,String corpid){
        if (CollectionUtils.isEmpty(list)){
            return;
        }

        //封装动态信息
        List<SimpleDynamicEntity> insertList = list.stream().map(item -> {
            SimpleDynamicEntity simpleDynamicEntity = new SimpleDynamicEntity();
            long now = DateUtil.getInt();
            //基本信息封装
            simpleDynamicEntity.setCorpid(corpid);
            simpleDynamicEntity.setDataId(item.getDataId());
            simpleDynamicEntity.setCreatorId(item.getCreatorId());
            simpleDynamicEntity.setLogType(item.getLogType());
            simpleDynamicEntity.setDel(DelEnum.NORMAL.getDel());
            simpleDynamicEntity.setAddTime(now);
            simpleDynamicEntity.setUpdateTime(now);
            simpleDynamicEntity.setBusinessType(item.getBusinessType());
            //解析memo
            String memo = item.getMemo();
            if (CollectionUtils.isNotEmpty(item.getMemoPlaceHolder())) {
                memo = String.format(I18nMessageUtil.getMessage(memo),item.getMemoPlaceHolder().toArray());
            }
            simpleDynamicEntity.setMemo(memo);
            //封装关联信息
            if (Objects.nonNull(item.getRefId()) && item.getRefId() != 0L){
                simpleDynamicEntity.setRefId(item.getRefId());
                simpleDynamicEntity.setRefBusinessType(item.getRefBusinessType());
                simpleDynamicEntity.setRefName(item.getRefName());
            }
            return simpleDynamicEntity;
        }).collect(Collectors.toList());
        //批量插入动态信息
        simpleDynamicModel.insertBatch(insertList);

    }

    /**
     * 根据dynamicDTO填充 dynamicEntity
     * @param dtos
     * @param dynamicEntities
     * @param corpid
     */
    private void fillDynamicEntitysUseDTO(List<DynamicDTO> dtos, List<DynamicEntity> dynamicEntities, String corpid) {
        for (DynamicDTO dto : dtos) {
            DynamicEntity dynamicEntity = new DynamicEntity();
            long now = DateUtil.getInt();
            Long addTime = Objects.nonNull(dto.getAddTime()) ? dto.getAddTime() : now;
            Long updateTime = Objects.nonNull(dto.getUpdateTime()) ? dto.getUpdateTime() : now;
            dynamicEntity.setCorpid(corpid);
            dynamicEntity.setCustomerId(dto.getCustomerId());
            dynamicEntity.setOpportunityId(dto.getOpportunityId());
            dynamicEntity.setContactId(dto.getContactId());
            dynamicEntity.setContractId(dto.getContractId());

            dynamicEntity.setCreatorId(dto.getCreatorId());
            dynamicEntity.setLogType(dto.getLogType());
            // 解析 memo信息
            String memo = dto.getMemo();
            if (CollectionUtils.isNotEmpty(dto.getMemoPlaceHolder())) {
                memo = String.format(I18nMessageUtil.getMessage(memo), dto.getMemoPlaceHolder().toArray());
            }
            dynamicEntity.setMemo(memo);
            if ((Objects.nonNull(dto.getRefId()) && dto.getRefId() != 0L) || Objects.equals(dto.getRefBusinessType(),XbbRefTypeEnum.CALL_CENTER.getCode())) {
                dynamicEntity.setRefId(dto.getRefId());
                dynamicEntity.setRefBusinessType(dto.getRefBusinessType());
                String refName = dto.getRefName();
                dynamicEntity.setRefName(refName);
            }
            dynamicEntity.setAddTime(addTime);
            dynamicEntity.setUpdateTime(updateTime);
            dynamicEntity.setDel(DelEnum.NORMAL.getDel());
            dynamicEntities.add(dynamicEntity);
        }
    }


    /**
     * 向上游填充数据
     * @param dynamicSaveDTO
     * @param refTextToLogTypeMap
     * @param paasForm 可以为空，方法内有查询
     * @param dynamicRefInfoDTO 若有关联必须实例化并设置内容
     * @param logType
     */
    protected void saveRefUpDynamic(DynamicSaveDTO dynamicSaveDTO, Map<String, Integer> refTextToLogTypeMap,
                                    PaasFormEntity paasForm, DynamicRefInfoDTO dynamicRefInfoDTO, Integer logType) {
        String memo;
        SaasFormSaveDTO saasFormSaveDTO = dynamicSaveDTO.getSaasFormSaveDTO();
        if (Objects.equals(saasFormSaveDTO.getIsImport(), BasicConstant.ONE)) {
            memo = CrmLogMemoConstant.DYNAMIC_USER_IMPORT;
        } else {
            memo = CrmLogMemoConstant.DYNAMIC_USER_ADD;
        }
        saveRefUpDynamic(dynamicSaveDTO, refTextToLogTypeMap, paasForm, dynamicRefInfoDTO, memo, null, logType);
    }

    /**
     * 向上游填充数据
     * @param dynamicSaveDTO
     * @param refTextToLogTypeMap
     * @param paasForm 可以为空，方法内有查询
     * @param dynamicRefInfoDTO
     * @param memo
     * @param memoPlaceholder 若有关联必须实例化并设置内容
     * @param logType
     */
    protected void saveRefUpDynamic(DynamicSaveDTO dynamicSaveDTO, Map<String, Integer> refTextToLogTypeMap,
                                    PaasFormEntity paasForm, DynamicRefInfoDTO dynamicRefInfoDTO, String memo, List<String> memoPlaceholder, Integer logType) {
        SaasFormSaveDTO saasFormSaveDTO = dynamicSaveDTO.getSaasFormSaveDTO();
        UserEntity creator = dynamicSaveDTO.getCreator();
        JSONObject newData = saasFormSaveDTO.getNewData();
        Long formId;
        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), saasFormSaveDTO.getBusinessType())) {
            formId = saasFormSaveDTO.getNewWorkOrderEntity().getFormId();
        } else {
            formId = saasFormSaveDTO.getNewPaasFormDataEntity().getFormId();
        }
        PaasFormEntity finalPaasForm = Objects.isNull(paasForm) ? getPaasForm(saasFormSaveDTO.getCorpid(), formId, saasFormSaveDTO.getBusinessType()) : paasForm;
        List<String> memoPh = CollectionUtils.isEmpty(memoPlaceholder) && I18nMessageUtil.getMessage(memo).contains("%s") ? DynamicDTO.initMemoHolder(creator.getName(), finalPaasForm.getName(), dynamicRefInfoDTO.getRefName()) : memoPlaceholder;

        DynamicRefInfoDTO refInfoDTO = Objects.nonNull(dynamicRefInfoDTO) ? dynamicRefInfoDTO : new DynamicRefInfoDTO();
        DynamicDTO dynamicDTO = initDynamicDTO(creator.getUserId(), memo, logType, memoPh, finalPaasForm, null, refInfoDTO.getRefId());
        BeanUtil.copyProperties(refInfoDTO, dynamicDTO, true);

        List<DynamicDTO> dynamicDTOS = parseRefUpData(dynamicDTO, refTextToLogTypeMap, newData,
                creator.getUserId(), memo, memoPh, finalPaasForm, null, refInfoDTO, saasFormSaveDTO.getBusinessType(), OperateTypeEnum.NEW);

        insertDynamic(dynamicDTOS, saasFormSaveDTO.getCorpid());
    }

    /**
     * 是否是主业务类型（客户、机会、联系人、合同）
     * @param businessType
     * @return
     */
    public boolean isMainBusinessType(Integer businessType) {
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        switch (xbbRefTypeEnum) {
            case CUSTOMER_MANAGEMENT:
            case CONTRACT:
            case SALES_OPPORTUNITY:
            case CONTACT:
                return true;
            default:
                return false;
        }
    }

    /**
     * 上游插入数据：因为批量删除引起的关联插入， 删除不需要具体的关联信息
     * @param dynamicDeleteDTO
     * @param refTextToLogTypeMap
     * @param paasForm 可以为空，方法内里面会有查询
     * @param deleteName 关联的要删除的数据的名称（或编号）标识 eg：ContractBaseEnum.CONTRACT_NO.getAttr(), 这里如果根据其查询结果为空，则直接获取编号
     */
    protected void batchRefSaveUpDynamicByDeleteBatch(DynamicDeleteDTO dynamicDeleteDTO, Map<String, Integer> refTextToLogTypeMap,
                                                      PaasFormEntity paasForm, String deleteName, Integer logType) {
        FormDataDeleteBatchDTO formDataDeleteBatchDTO = dynamicDeleteDTO.getFormDataDeleteBatchDTO();
        List<PaasFormDataEntityExt> allowDeletePaasFormDatas = dynamicDeleteDTO.getAllowDeletePaasFormDatas();

        if (CollectionUtils.isEmpty(allowDeletePaasFormDatas)) {
            return;
        }

        PaasFormEntity finalPaasForm = Objects.isNull(paasForm) ? getPaasForm(formDataDeleteBatchDTO.getCorpid(), formDataDeleteBatchDTO.getFormId(), formDataDeleteBatchDTO.getBusinessType()) : paasForm;

        List<DynamicDTO> insertDynamics = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (PaasFormDataEntityExt allowDeletePaasFormData : allowDeletePaasFormDatas) {
            String dataName = allowDeletePaasFormData.getData().getString(deleteName);
            if (Objects.isNull(dataName)) {
                dataName = allowDeletePaasFormData.getSerialNo();
                if (StringUtil.isEmpty(dataName)) {
                    dataName = "--";
                }
            }
            List<String> memoPlaceHolder = DynamicDTO.initMemoHolder(formDataDeleteBatchDTO.getLoginUserName(), finalPaasForm.getName(), dataName);
            // 客户旅程发现修复 logType
            DynamicDTO dynamicDTO = initDynamicDTO(formDataDeleteBatchDTO.getUserId(), CrmLogMemoConstant.DYNAMIC_USER_DELETE_DETAIL, logType, memoPlaceHolder,
                    finalPaasForm, formDataDeleteBatchDTO.getSaasMark(), null);

            List<DynamicDTO> dynamicDTOS = parseRefUpData(dynamicDTO, refTextToLogTypeMap, allowDeletePaasFormData.getData(),
                    formDataDeleteBatchDTO.getUserId(), CrmLogMemoConstant.DYNAMIC_USER_DELETE_DETAIL,
                    memoPlaceHolder,
                    finalPaasForm, formDataDeleteBatchDTO.getSaasMark(), null, formDataDeleteBatchDTO.getBusinessType(), OperateTypeEnum.DELETE);
            insertDynamics.addAll(dynamicDTOS);
        }
        insertDynamic(insertDynamics, formDataDeleteBatchDTO.getCorpid());
    }

    /**
     *
     * @param dynamicDTO
     * @param refTextToLogTypeMap
     * @param newData
     * @param userId
     * @param memo 没有填充%s的字符串
     * @param memoPlaceHolder
     * @param finalPaasForm
     * @param saasMark
     * @param dynamicRefInfoDTO
     * @param businessType
     * @param operateTypeEnum
     */
    private List<DynamicDTO> parseRefUpData(DynamicDTO dynamicDTO, Map<String, Integer> refTextToLogTypeMap, JSONObject newData,
                                            String userId, String memo, List<String> memoPlaceHolder,
                                            PaasFormEntity finalPaasForm, Integer saasMark, DynamicRefInfoDTO dynamicRefInfoDTO, Integer businessType, OperateTypeEnum operateTypeEnum) {
        // 关联项可能存在 JSONArray 类型，不考虑回查，直接按照 JSONArray.size -1 填充动态
        Map<String, Map<Integer, List<Long>>> refTypeToSubTypeToDataIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        AtomicBoolean hasParentIdDynamic = new AtomicBoolean(false);
        refTextToLogTypeMap.forEach((refText, subType) -> {
            Object refData = newData.get(refText);
            Long refDataId = null;
            if (Objects.nonNull(refData) && refData instanceof Collection) {
                JSONArray jsonArray = newData.getJSONArray(refText);
                List<Long> refDataIds = jsonArray.toJavaList(Long.class);
                if (CollectionUtils.isNotEmpty(refDataIds)) {
                    for (int i = 0; i < refDataIds.size(); i++) {
                        if (i == 0) {
                            refDataId = refDataIds.get(0);
                        } else {
                            refTypeToSubTypeToDataIdMap.computeIfAbsent(refText, k -> new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY)).computeIfAbsent(subType, k -> new ArrayList<>()).add(refDataIds.get(i));
                        }
                    }
                }
            } else {
                refDataId = newData.getLong(refText);
            }
            if (Objects.nonNull(refDataId)) {
                hasParentIdDynamic.set(true);
                initMainBusinessIdOrRefIdByLogType(subType, dynamicDTO, refDataId);
            }
        });

        List<DynamicDTO> dynamicDTOS = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (Map.Entry<String, Map<Integer, List<Long>>> refTextMap : refTypeToSubTypeToDataIdMap.entrySet()) {
            for (Map.Entry<Integer, List<Long>> subTypeMap : refTextMap.getValue().entrySet()) {
                Integer subType = subTypeMap.getKey();
                List<Long> dataIds = subTypeMap.getValue();
                if (CollectionUtils.isNotEmpty(dataIds)) {
                    for (Long dataId : dataIds) {
                        DynamicDTO dto = initDynamicDTO(userId, memo, subType, memoPlaceHolder, finalPaasForm, saasMark, dataId);
                        // 客户旅程发现修复 logType
                        Integer logType = dynamicDTO.getLogType();
                        if (Objects.nonNull(logType)) {
                            dto.setLogType(logType);
                        }
                        if (Objects.nonNull(dynamicRefInfoDTO)) {
                            BeanUtil.copyProperties(dynamicRefInfoDTO, dto, true);
                        }
                        dynamicDTOS.add(dto);
                    }
                }
            }
        }
        // 当前操作关系到是否需要插入动态到当前业务，比如联系人删除操作，就不需要添加联系人删除动态而是将联系人删除动态关联显示到上游如客户
        boolean operateCanInsertDynamic = !Objects.equals(operateTypeEnum, OperateTypeEnum.DELETE);
        // 有上游
        if (Boolean.TRUE.equals(hasParentIdDynamic.get())) {
            dynamicDTOS.add(dynamicDTO);
        }
        // 无上游
        else if (Boolean.FALSE.equals(hasParentIdDynamic.get()) && isMainBusinessType(businessType) && operateCanInsertDynamic) {
            dynamicDTOS.add(dynamicDTO);
        }
        return dynamicDTOS;
    }
    /**
     * 获取表单信息（包含被删除）
     * @param corpid
     * @param formId
     * @param businessType
     * @return
     */
    protected PaasFormEntity getPaasForm(String corpid, Long formId, Integer businessType) {
        try {
            if (Objects.isNull(corpid) || Objects.isNull(formId) || Objects.isNull(businessType)) {
                return new PaasFormEntity();
            }
            return proFormHelp.getPaasFormIncludeDel(formId, businessType, corpid);
        } catch (Exception e) {
            return new PaasFormEntity();
        }
    }

    /**
     * 根据业务类型，设置主业务（客户、合同、联系人、机会）或关联的id
     * @param businessType
     * @param dynamicDTO
     * @param mainBusinessId
     * @return
     */
    protected static void initMainBusinessIdOrRefIdByBusinessType(Integer businessType, DynamicDTO dynamicDTO, Long mainBusinessId) {
        if (Objects.nonNull(businessType) && Objects.nonNull(dynamicDTO)) {
            XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
            switch (xbbRefTypeEnum) {
                case CUSTOMER_MANAGEMENT:
                    dynamicDTO.setCustomerId(mainBusinessId);
                    break;
                case CONTRACT:
                    dynamicDTO.setContractId(mainBusinessId);
                    break;
                case CONTACT:
                    dynamicDTO.setContactId(mainBusinessId);
                    break;
                case SALES_OPPORTUNITY:
                    dynamicDTO.setOpportunityId(mainBusinessId);
                    break;
                case COMPETITOR:
                    dynamicDTO.setDataId(mainBusinessId);
                    break;
                default:
                    dynamicDTO.setRefId(mainBusinessId);
                    break;
            }
        }
    }

    /**
     * 根据日志类型，设置主业务（客户、合同、联系人、机会）或关联的id
     * @param logType ProjectLogEnum
     * @param dynamicDTO
     * @param mainBusinessId
     */
    protected static void initMainBusinessIdOrRefIdByLogType(Integer logType, DynamicDTO dynamicDTO, Long mainBusinessId) {
        if (Objects.nonNull(logType) && Objects.nonNull(dynamicDTO) && Objects.nonNull(mainBusinessId)) {
            Integer businessType = ProjectLogEnum.getBusinessTypeCodeBySubType(logType);
            initMainBusinessIdOrRefIdByBusinessType(businessType, dynamicDTO, mainBusinessId);
        }
    }

    protected DynamicDTO initDynamicDTO(String creatorId, String memo, Integer logType, List<String> memoPlaceHolder, PaasFormEntity paasFormEntity, Integer saasMark, Long dataId) {
        DynamicDTO dynamicDTO = DynamicDTO.initDynamicDTO(creatorId, memo, logType, memoPlaceHolder, paasFormEntity, saasMark);
        initMainBusinessIdOrRefIdByLogType(logType, dynamicDTO, dataId);
        return dynamicDTO;
    }








    @Async("dynamicThreadPool")
    public void deleteBatchLinkData(List<DynamicDeleteLinkData> list){
        try {
            if(CollectionUtils.isEmpty(list)){
                return;
            }
            DynamicDeleteLinkData dynamicDeleteLinkData = list.get(0);
            Long linkDataFormId = dynamicDeleteLinkData.getFormId();
            String userName = dynamicDeleteLinkData.getUserName();
            // Long dataId = dynamicDeleteLinkData.getDataId();

            String userId = dynamicDeleteLinkData.getUserId();
            String corpid = dynamicDeleteLinkData.getCorpid();
            String paasFormName = dynamicDeleteLinkData.getPaasFormName();
            Integer deleteBusinessType = null;
            if(StringUtil.isEmpty(paasFormName)){
                PaasFormEntity paasFormEntity =  paasFormModel.getByKey(linkDataFormId, corpid);
                if (Objects.nonNull(paasFormEntity)) {
                    deleteBusinessType = paasFormEntity.getBusinessType();
                    paasFormName = paasFormEntity.getName();
                }
            }
            Integer finalDeleteBusinessType = deleteBusinessType;
            String finalPaasFormName = paasFormName;
            List<DynamicEntity> dynamicEntityList = new ArrayList<>();
            //简单动态
            List<SimpleDynamicEntity> simpleDynamicEntityList = new ArrayList<>();
            list.forEach(temp->{
                String name = temp.getName();
                Integer parentBusinessType = temp.getParentBusinessType();
                Long parentDataId = temp.getParentDataId();
                String memo;
                if (Objects.equals(XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode(), finalDeleteBusinessType)) {
                    PaasFormDataEntityExt deletePaasFormData = temp.getDeletePaasFormData();
                    JSONObject data = deletePaasFormData.getData();
                    // 跟进信息
                    String communicateInfo = data.getString(CommunicateBaseEnum.MEMO.getAttr());
                    communicateInfo = StringUtil.isEmpty(communicateInfo) ? "--" : communicateInfo;
                    // 跟进时间
                    String communicateDateTime = DateTimeUtil.getStringEpochSecond(data.getLong(CommunicateBaseEnum.COMMUNICATE_TIME.getAttr()), DateTimeUtil.SDFYMDHM);
                    memo = String.format(I18nMessageUtil.getMessage(CrmLogMemoConstant.DYNAMIC_USER_COMMUNICATE_DELETE),
                            userName, communicateDateTime, communicateInfo);
                } else {
                    memo = String.format(I18nMessageUtil.getMessage(CrmLogMemoConstant.DYNAMIC_LINK_DATA_DELETE),
                            userName, finalPaasFormName, name);
                }
                //竞争对手动态添加到简单动态表中
                if (Objects.equals(parentBusinessType,XbbRefTypeEnum.COMPETITOR.getCode())){
                    SimpleDynamicEntity simpleDynamicEntity = new SimpleDynamicEntity();
                    simpleDynamicEntity.setCorpid(corpid);
                    simpleDynamicEntity.setMemo(memo);
                    simpleDynamicEntity.setCreatorId(userId);
                    simpleDynamicEntity.setLogType(ProjectLogEnum.PAAS_DELETE.getSubType());
                    simpleDynamicEntity.setDataId(parentDataId);
                    simpleDynamicEntityList.add(simpleDynamicEntity);
                }else {
                    DynamicEntity dynamicEntity = new DynamicEntity(corpid,null,memo,
                            userId,ProjectLogEnum.PAAS_DELETE.getSubType());
                    dynamicSetId(parentBusinessType,parentDataId,dynamicEntity);
                    dynamicEntityList.add(dynamicEntity);
                }
            });


            if (CollectionUtils.isNotEmpty(simpleDynamicEntityList)){
                simpleDynamicModel.insertBatch(simpleDynamicEntityList);
            }else {
                dynamicModel.insertBatch(dynamicEntityList);
            }

        }catch (Exception e){
            LOG.error("com.xbongbong.paas.service.dynamic.crm.strategy.AbstractDynamicStrategy.deleteBatchLinkData",e);
        }
    }

    @Async("dynamicThreadPool")
    public void linkDataStageJump(List<DynamicLinkDataStageJump> list){
        try {
            if(CollectionUtils.isEmpty(list)){
                return;
            }
            DynamicLinkDataStageJump dynamicLinkDataStageJump = list.get(0);
            String paasFormName = dynamicLinkDataStageJump.getPaasFormName();
            String userId = dynamicLinkDataStageJump.getUserId();
            String corpid = dynamicLinkDataStageJump.getCorpid();
            String name = dynamicLinkDataStageJump.getName();
            String userName = dynamicLinkDataStageJump.getUserName();
            Long linkDataFormId = dynamicLinkDataStageJump.getFormId();
            Long dataId = dynamicLinkDataStageJump.getDataId();
            String fromStageName = dynamicLinkDataStageJump.getFromStageName();
            String toStageName = dynamicLinkDataStageJump.getToStageName();

            if(StringUtil.isEmpty(paasFormName)){
                PaasFormEntity paasFormEntity =  paasFormModel.getByKey(linkDataFormId, corpid);
                paasFormName = paasFormEntity.getName();
            }
            List<DynamicEntity> dynamicEntityList = new ArrayList<>();
            String finalPaasFormName = paasFormName;
            list.forEach(temp->{
                Integer parentBusinessType = temp.getParentBusinessType();
                Long parentDataId = temp.getParentDataId();
                String memo = String.format(I18nMessageUtil.getMessage(CrmLogMemoConstant.DYNAMIC_LINK_DATA_STAGE_JUMP),
                        userName, finalPaasFormName, name,fromStageName,toStageName);
                DynamicEntity dynamicEntity = new DynamicEntity(corpid,dataId,temp.getBusinessType(),name,memo,
                        userId,ProjectLogEnum.PAAS_ADD.getSubType());
                dynamicSetId(parentBusinessType,parentDataId,dynamicEntity);
                dynamicEntityList.add(dynamicEntity);
            });
            dynamicModel.insertBatch(dynamicEntityList);
        }catch (Exception e){
            LOG.error("com.xbongbong.paas.service.dynamic.crm.strategy.AbstractDynamicStrategy.linkDataStageJump",e);
        }
    }

    @Async("dynamicThreadPool")
    public void addBatch(DynamicPushNotifyAddDTO dynamicPushNotifyAddDTO){
        //张三 新建了 [表单或模板名称]：[对象名称]
        FormDataAddDTO formDataAddDTO = dynamicPushNotifyAddDTO.getFormDataAddDTO();
        List<Integer> dataIdList = formDataAddDTO.getDataIdList();
        String loginUserName = formDataAddDTO.getLoginUserName();
        String userId = formDataAddDTO.getUserId();
        String corpid = formDataAddDTO.getCorpid();
        JSONObject dataList = formDataAddDTO.getDataList();
        Integer type = dynamicPushNotifyAddDTO.getLinkBusinessType();

        // 跟进提醒没有详情页
        // Map<String, Object> param = pushModel.pushNotifyParam(dataIdList.stream().map(Integer::longValue).collect(Collectors.toList()), corpid, type, DateUtil.getInt(), null);
        // Map<Long, PushEntity> refIdToPushMap = pushModel.findEntitys(param).stream().collect(Collectors.toMap(PushEntity::getRefId, item -> item));

        String title = dataList.getString(CommunicateBaseEnum.MAIN_BUSINESS.getAttr());

        List<DynamicEntity> dynamicEntityList = new ArrayList<>();

        if (dataIdList == null ) {
            dataIdList = new ArrayList<>(1);
            if (formDataAddDTO.getNotifyNeedDataId() != null) {
                // 。。。。。。
                dataIdList.add(formDataAddDTO.getNotifyNeedDataId().intValue());
            }
        }
        dataIdList.forEach(refId->{
            //%s 新建了 %s： %s
            String memo = String.format(I18nMessageUtil.getMessage(CrmLogMemoConstant.DYNAMIC_LINK_DATA_ADD)+": %s",
                    loginUserName, I18nMessageUtil.getMessage(OperateModuleTypeEnum.PUSH_NOTIFY.getName()), title);
            // 跟进提醒不需要设置ref_id等信息
            DynamicEntity dynamicEntity = new DynamicEntity(corpid,null,null
                    ,null,memo,
                    userId,ProjectLogEnum.PUSH_NOTIFY_ADD.getSubType());
            dynamicSetId(type,(long)refId,dynamicEntity);
            dynamicEntityList.add(dynamicEntity);
        });
        dynamicModel.insertBatch(dynamicEntityList);

    }

    @Async("dynamicThreadPool")
    public void delete(DynamicPushNotifyDeleteDTO dynamicPushNotifyDeleteDTO){
        //张三 删除了[表单或模板名称]：[对象名称]
        try {
            DelRemindDTO deleteRemind = dynamicPushNotifyDeleteDTO.getDeleteRemind();
            Long dataId = deleteRemind.getDataId();
            String corpid = deleteRemind.getCorpid();
            String userId = deleteRemind.getUserId();
            String loginUserName = deleteRemind.getLoginUserName();
            PushEntity pushEntity =  pushModel.getByKey(dataId.intValue(),corpid);
            Long refId = pushEntity.getRefId();
            Integer type = pushEntity.getType();

            String msg = pushEntity.getMsg();
            OA oa = JSONObject.parseObject(msg, OA.class);
            if (Objects.isNull(oa)) {
                oa = new OA();
            }
            OA.Body body = oa.getBody() == null ? new OA.Body() : oa.getBody();
            String title = body.getTitle();
            String memo = String.format(I18nMessageUtil.getMessage(CrmLogMemoConstant.DYNAMIC_LINK_DATA_DELETE),
                    loginUserName, I18nMessageUtil.getMessage(OperateModuleTypeEnum.PUSH_NOTIFY.getName()), title);

            DynamicEntity dynamicEntity = new DynamicEntity(corpid,null,null
                    ,null,memo,
                    userId,ProjectLogEnum.PUSH_NOTIFY_DELETE.getSubType());
            dynamicSetId(type,refId,dynamicEntity);

            dynamicModel.insert(dynamicEntity);
        }catch (Exception e){
            LOG.error("com.xbongbong.paas.service.log.help.OperationLogHelp.deletePushNotify",e);
        }

    }





    /**
     * 决策树提醒
     * date: 2022/5/25 1:46 下午
     * @param dynamicPushNotifyAddDTO:
     */
    @Async("dynamicThreadPool")
    public void addOrDelete(DynamicDecisionTreeDTO dynamicPushNotifyAddDTO){
        try {
            DecisionTreeSaveDTO decisionTreeSaveDTO = dynamicPushNotifyAddDTO.getDecisionTreeSaveDTO();
            String corpid = decisionTreeSaveDTO.getCorpid();
            String loginUserName = decisionTreeSaveDTO.getLoginUserName();
            String userId = decisionTreeSaveDTO.getUserId();
            Long dataId = decisionTreeSaveDTO.getDataId();
            // Long formId = decisionTreeSaveDTO.getFormId();
            Integer businessType = decisionTreeSaveDTO.getBusinessType();
            boolean isNew = dynamicPushNotifyAddDTO.isNew();
            String dynamicObject = null;
            if(Objects.equals(XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(),businessType)){
                dynamicObject = I18nMessageUtil.getMessage(CrmLogMemoConstant.DYNAMIC_DECISION_TREE);
            }
            if(Objects.equals(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(),businessType)){
                dynamicObject = I18nMessageUtil.getMessage(CrmLogMemoConstant.DYNAMIC_CONTACT_ORGANIZATION_TREE);
            }
            //1新增  2 删除
            String option = null;
            if(isNew){
                option = I18nStringConstant.ADD;
            }else{
                option = I18nStringConstant.UPDATE;
            }
            String memo = loginUserName+I18nMessageUtil.getMessage(option)+dynamicObject;
            DynamicEntity dynamicEntity = new DynamicEntity(corpid,null,XbbRefTypeEnum.PUSH_NOTIFY.getCode()
                    ,null,memo,
                    userId,ProjectLogEnum.PUSH_NOTIFY_DELETE.getSubType());
            dynamicSetId(businessType,dataId,dynamicEntity);
            dynamicModel.insert(dynamicEntity);
        }catch (XbbException e){
            LOG.error("com.xbongbong.paas.service.dynamic.crm.strategy.AbstractDynamicStrategy.addOrDelete",e);
        }

    }

    protected void label(DynamicLabelDTO dynamicLabelDTO, Integer logType) {
        AddLabelDTO addLabelDTO = dynamicLabelDTO.getAddLabelDTO();
        List<Long> dataIds = addLabelDTO.getDataIdList();
        if (CollectionUtils.isEmpty(dataIds) || !isMainBusinessType(addLabelDTO.getBusinessType())) {
            return;
        }
        Boolean addOrDelete = dynamicLabelDTO.getAddOrDelete();
        String memo;
        // 批量化
        if (Boolean.TRUE.equals(addOrDelete)) {
            memo = CrmLogMemoConstant.DYNAMIC_USER_LABEL_ADD;
        } else {
            memo = CrmLogMemoConstant.DYNAMIC_USER_LABEL_DELETE;
        }

        List<Long> labelIds = addLabelDTO.getLabelIds();
        List<String> labelList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (CollectionUtils.isNotEmpty(labelIds)) {
            List<LabelEntity> labelEntityList = labelModel.getByLabelIds(labelIds, addLabelDTO.getCorpid());
            labelEntityList.forEach(labelEntity -> labelList.add(labelEntity.getName()));
            String labelName = StringUtils.join(labelList, "，");
            List<DynamicDTO> dynamicDTOS = new ArrayList<>(dataIds.size());
            for (Long dataId : dataIds) {
                DynamicDTO dynamicDTO = initDynamicDTO(addLabelDTO.getUserId(), memo, logType, DynamicDTO.initMemoHolder(addLabelDTO.getLoginUserName(), labelName), null, addLabelDTO.getSaasMark(), dataId);
                dynamicDTOS.add(dynamicDTO);
            }
            insertDynamic(dynamicDTOS, addLabelDTO.getCorpid());
        }
    }

    /**
     * 根据业务类型查询关联数据字段
     * @param businessType
     * @return
     */
    protected Map<String, Integer> getRefTextToLogTypeMap(Integer businessType){
        Map<String, Integer> map = new HashMap<>(0);
        XbbRefTypeEnum byCode = XbbRefTypeEnum.getByCode(businessType);
        switch (byCode){
            case CONTRACT:
                return ContractDynamicStrategyImpl.getRefTextToLogTypeMap();
            case SALES_OPPORTUNITY:
                return OpportunityDynamicStrategyImpl.getRefTextToLogTypeMap();
            case CONTACT:
                return ContactDynamicStrategyImpl.getRefTextToLogTypeMap();
            case WORK_ORDER:
                return WorkOrderDynamicStrategyImpl.getRefTextToLogTypeMap();
            case INVOICE:
                return InvoiceDynamicStrategyImpl.getRefTextToLogTypeMap();
            case QUOTATION:
                return QuotationDynamicStrategyImpl.getRefTextToLogTypeMap();
            case REFUND:
                return RefundDynamicStrategyImpl.getRefTextToLogTypeMap();
            case PAYMENT:
                return PayDynamicStrategyImpl.getRefTextToLogTypeMap();
            case COMMUNICATE_PLAN:
                return CommunicatePlanDynamicStrategyImpl.getRefTextToLogTypeMap();
            case PAYMENT_SHEET:
            case WRITE_OFF_PREPAYMENT:
            case PREPAYMENT:
            case RED_PREPAYMENT:
            case RED_PAYMENT_SHEET:
            case RED_WRITE_OFF_PREPAYMENT:
            case RED_WRITE_OFF_BALANCE:
            case BAD_DEBT:
                return PaymentSheetDynamicStrategyImpl.getRefTextToLogTypeMap();
            default:
                return map;
        }
    }
}
